package net.zf.dynamic.threadpool.config;

import net.zf.dynamic.threadpool.bean.DynamicThreadPoolContext;
import net.zf.dynamic.threadpool.bean.ThreadPoolConfigEntity;
import net.zf.dynamic.threadpool.redis.RedisProperty;
import net.zf.dynamic.threadpool.redis.RedisRegistry;
import net.zf.dynamic.threadpool.task.ThreadPoolDataReportTask;
import net.zf.dynamic.threadpool.util.ThreadPoolRegistryEnum;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 动态线程池配置类
 *
 * @author tengyd
 */
@EnableConfigurationProperties(RedisProperty.class)
@Configuration
@EnableScheduling
public class DynamicThreadPoolAutoConfig {

    private static final Logger log = LoggerFactory.getLogger(DynamicThreadPoolAutoConfig.class);

    @Bean("dynamicRedissonClient")
    public RedissonClient redissonClient(RedisProperty redisProperty) {
        Config config = new Config();
        config.setCodec(JsonJacksonCodec.INSTANCE);

        config.useSingleServer().setAddress("redis://" + redisProperty.getHost() + ":" + redisProperty.getPort()).setPassword(redisProperty.getPassword()).setDatabase(0);

        return Redisson.create();
    }

    @Bean("redisRegistry")
    public RedisRegistry redisRegistry(RedissonClient dynamicRedissonClient) {
        return new RedisRegistry(dynamicRedissonClient);
    }



    /**
     * 创建动态线程池上下文
     *
     * @param applicationContext
     * @param threadPoolExecutorMap
     * @return
     */
    @Bean
    public DynamicThreadPoolContext dynamicThreadPoolContext(ApplicationContext applicationContext, Map<String, ThreadPoolExecutor> threadPoolExecutorMap, RedissonClient dynamicRedissonClient) {
        String applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");

        if (applicationName.isEmpty()) {
            applicationName = "default";
            log.warn("未配置应用名称！默认设置为default");
        }

        Set<String> threadPoolSet = threadPoolExecutorMap.keySet();
        for (String threadPoolName : threadPoolSet) {
            RBucket<ThreadPoolConfigEntity> threadPoolConfigBucket = dynamicRedissonClient.getBucket(ThreadPoolRegistryEnum.THREAD_POOL_CONFIG_PARAM + ":" + applicationName + ":" + threadPoolName);
            ThreadPoolConfigEntity threadPoolConfig = threadPoolConfigBucket.get();
            if (threadPoolConfig == null) continue;
            log.info("threadPoolName:{}", threadPoolName);

            ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolName);
            log.info("threadPoolConfig: {}", threadPoolConfig);

            threadPoolExecutor.setCorePoolSize(threadPoolConfig.getCorePoolSize());
            threadPoolExecutor.setMaximumPoolSize(threadPoolConfig.getMaxPoolSize());

        }

        return new DynamicThreadPoolContext(applicationName, threadPoolExecutorMap);
    }

    @Bean
    public ThreadPoolDataReportTask threadPoolDataReportTask(RedisRegistry redisRegistry, DynamicThreadPoolContext dynamicThreadPoolContext) {
        return new ThreadPoolDataReportTask(redisRegistry, dynamicThreadPoolContext);
    }
}
